(* Written by Zachary Salzbank *)

open Ast

type simple_expr =
    Literal of Ast.constant 
  | LValue of l_value
  | Node of simple_expr
  | Binop of expr * Ast.op * expr
  | Assign of l_value * expr
  | Call of func_decl * expr list
  | Neg of expr
  | Bang of expr
  | Noexpr

and unary_op = Child of expr | ValueOf

and simple_l_value =
    Id of v_decl
  | Unop of l_value * unary_op

and stmt =
    Block of v_decl list * stmt list
  | Expr of expr
  | Return of expr
  | If of expr * stmt * stmt
  | While of expr * stmt

and expr = simple_expr * Ast.obj_type

and l_value = simple_l_value * Ast.obj_type

and v_decl = {
  vvname: string;
  vvtype: Ast.obj_type;
  vvdefault: expr option;
}

and func_decl = {
  fftype: Ast.obj_type;
  ffname : string;
  fformals : v_decl list;
  flocals : v_decl list;
  fbody : stmt list;
  parsed: bool;
}

type program = v_decl list * func_decl list

let string_of_sast_v v = 
  "Variable: " ^ v.vvname ^ " = " ^ string_of_obj_type v.vvtype ^ "\n"

let string_of_sast_f f = 
  "Function: " ^ f.ffname ^ " = " ^ string_of_obj_type f.fftype ^
  String.concat "\n\t" ("\nFormals: " :: (List.map string_of_sast_v f.fformals)) ^
  String.concat "\n\t" ("\nLocals: " :: (List.map string_of_sast_v f.flocals))


let string_of_sast (vars, funcs) = 
  String.concat "" (List.map string_of_sast_v vars) ^ "\n" ^
  String.concat "\n" (List.map string_of_sast_f funcs)
